using System;
using Microsoft.SPOT;
using System.Threading;
using System.Collections;

namespace N2Plus_GPS
{
    /// <summary>
    /// Timer class to record the race information
    /// </summary>
    public class Racetimer
    {
        #region Private Variables
        /// <summary>
        /// Lap time object for calculating laptimes
        /// </summary>
        private TimeSpan _CurrentLapTime = default(TimeSpan);
        /// <summary>
        /// Stores the last laptime recorded
        /// </summary>
        private TimeSpan _LastLapTime = default(TimeSpan);
        /// <summary>
        /// Last sector time recorded
        /// </summary>
        private TimeSpan _LastSectorTime = default(TimeSpan);
        /// <summary>
        /// Sector time object for calculating sector time
        /// </summary>
        private TimeSpan _CurrentSectorTime = default(TimeSpan);
        /// <summary>
        /// Lap Stopwatch Timer
        /// </summary>
        private Stopwatch _Stopwatch_Lap = null;
        /// <summary>
        /// Sector Stopwatch Timer
        /// </summary>
        private Stopwatch _Stopwatch_Sector = null;

        /// <summary>
        /// Saves the last sector that was passed to ensure we don't get multiple intersections
        /// </summary>
        private Sector _LastSector = null;
        /// /// <summary>
        /// Saves the Last Knows Sector Index
        /// </summary>
        private int LastSectorIndex = -1;
        /// <summary>
        /// The next expected sector so we don't process extra
        /// </summary>
        private Sector _NextExpectedSector = null;
        /// <summary>
        /// Stores the Start Finish Sector
        /// </summary>
        private Sector _StartFinish = null;
        #endregion

        #region Constructor
        /// <summary>
        /// Default Constructor
        /// </summary>
        public Racetimer()
        {

        }
        #endregion

        #region Properties
        /// <summary>
        /// Indicates how many laps have been done
        /// </summary>
        public int LapCounter
        {
            get;
            set;
        }

        private TimeSpan _FastestLap = default(TimeSpan);
        /// <summary>
        /// The fastest lap that has been done so far
        /// </summary>
        public TimeSpan FastestLap
        {
            get { return _FastestLap; }
            set { _FastestLap = value; }
        }

        private ArrayList _FastestLapSectors = null;
        /// <summary>
        /// Saves the fastest Lap Sectors to compare for differential timing
        /// </summary>
        public ArrayList FastestLapSectors
        {
            get { return _FastestLapSectors; }
            set { _FastestLapSectors = value; }
        }

        private Racetrack _Racetrack = null;
        /// <summary>
        /// Current Race track
        /// </summary>
        public Racetrack Racetrack
        {
            get { return _Racetrack; }
            set { _Racetrack = value; }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Update the timer to show if the gps point is updated
        /// </summary>
        /// <param name="pGPSPoint"></param>
        public void GPSPositionChanged(ref GPSPoint pGPSPoint)
        {
            //Verify valid GPS point
            if (Locator.IsValidGPSCoordinate(pGPSPoint))
            {

                bool lvFound = false;

                //Check which sector it could fall within
                //1. Always check start finish first
                if (_LastSector != _StartFinish)
                {
                    #region Start Finish
                    if (Locator.IsInSector(pGPSPoint,_StartFinish))
                    {
                        //Start finish was crossed
                        if (_Stopwatch_Lap == null)
                        {
                            //First Lap
                            LapCounter = 0;
                            _Stopwatch_Lap.Start();
                            _Stopwatch_Sector.Start();
                        }
                        else
                        {
                            //Not first lap
                            //Save last laptime
                            _Stopwatch_Lap.Stop();
                            _LastLapTime = _Stopwatch_Lap.Elapsed;
                            _Stopwatch_Lap.Reset();
                            _Stopwatch_Lap.Start();

                            //Save last sector time
                            _Stopwatch_Sector.Stop();
                            _LastSectorTime = _Stopwatch_Sector.Elapsed;
                            _Stopwatch_Sector.Reset();
                            _Stopwatch_Sector.Start();

                            //Increment Lap counter
                            LapCounter++;

                            if (_LastSector != null)
                            {
                                //Store the Last Sector Time
                                _LastSector.SectorTime = _LastSectorTime;
                            }

                            //Check if it was a faster laptime
                            if (_FastestLap == default(TimeSpan))
                            {
                                _FastestLap = _LastLapTime;
                            }
                            else
                            {
                                if (_LastLapTime < _FastestLap)
                                {
                                    //New fastest lap
                                    _FastestLap = _LastLapTime;

                                    //Update all the sector times to reflect their new fastest lap sector time
                                    foreach (Sector lvSector in _Racetrack.Sectors)
                                    {
                                        lvSector.FastestLapSectorTime = lvSector.SectorTime;
                                    }

                                    //Save the collection of sectors
                                    _FastestLapSectors = _Racetrack.Sectors;
                                }
                            }
                        }

                        _LastSector = _StartFinish;
                        _NextExpectedSector = (Sector)_Racetrack.Sectors[_StartFinish.SectorIndex + 1];

                        lvFound = true;
                    }
                    #endregion
                }

                if (!lvFound)
                {
                    //Check expected sector first
                    if (Locator.IsInSector(pGPSPoint, _NextExpectedSector))
                    {
                        _Stopwatch_Sector.Stop();
                        _LastSectorTime = _Stopwatch_Sector.Elapsed;
                        _Stopwatch_Sector.Reset();
                        _Stopwatch_Sector.Start();

                        _LastSector.SectorTime = _LastSectorTime;

                        int lvNextIndex = -1;
                        if (_LastSector.SectorIndex == _Racetrack.Sectors.Count - 1)
                        {
                            lvNextIndex = 0;
                        }
                        else
                        {
                            lvNextIndex = _LastSector.SectorIndex + 1;
                        }

                        _LastSector = _NextExpectedSector;
                        _NextExpectedSector = (Sector)_Racetrack.Sectors[lvNextIndex];
                        lvFound = true;
                    }
                }
            }
        }
        #endregion

        #region Overrides
        #endregion


    }
}
